<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
	<style>
		body {
			background-color: #bbb;
			color: #383838;
		}
		#canvas {
			background-color: #fff;
		}
	</style>
</head>
<body>
	<canvas id="canvas" width="600" height="600"></canvas>
	
	
	<script>
		function captureMouse(element){
			var mouse = {x: 0, y: 0};
			element.addEventListener('mousemove', function(event){
				var x, y;
				if(event.pageX || event.pageY){
					x = event.pageX;
					y = event.pageY;
				}else{
					x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
					y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
				}
				x -= element.offsetLeft;
				y -= element.offsetTop;
				
				mouse.x = x;
				mouse.y = y;
			}, false);
			element.addEventListener('mouseout', function(event){
				mouse.x = -999;
				mouse.y = -999;
			});
			return mouse;
		};
		
		var canvas = document.getElementById('canvas'),
				context = canvas.getContext('2d'),
				centerX = canvas.width,
				centerY = canvas.height,
				circles = [],
				numCircles = 30,
				spring = 0.03,
				mouse = captureMouse(canvas);
		
		class Ball{
			constructor(radius=40, color="#ccc") {
				this.x = 0;
				this.y = 0;
				this.radius = radius;
				this.rotation = 0;
				this.mass = 1;
				this.vx = 0;
				this.vy = 0;
				this.scaleX = 1;
				this.scaleY = 1;
				this.color = color;
				this.lineWidth = 1;
			}
			draw(context){
				context.save();
				context.translate(this.x, this.y);
				context.rotate(this.rotation);
				context.scale(this.scaleX, this.scaleY);
				context.lineWidth = this.lineWidth;
				context.strokeStyle = this.color;
				context.fillStyle = this.color;
				context.beginPath();
				context.arc(0,0,this.radius, 0, (Math.PI * 2), true);
				context.closePath();
				context.fill();
				if(this.lineWidth > 0){
					context.stroke();
				}
				context.restore();
			}
			getBounds(){
				return{
					x: this.x - this.radius,
					y: this.y - this.radius,
					width: this.radius * 2,
					height: this.radius * 2
				}
			}
		}		
		
		class Line{
			constructor(x1, y1, x2, y2) {
			  this.x = 0;
				this.y = 0;
				this.x1 = (x1 === undefined) ? 0 : x1;
				this.y1 = (y1 === undefined) ? 0 : y1;
				this.x2 = (x2 === undefined) ? 0 : x2;
				this.y2 = (y2 === undefined) ? 0 : y2;
				this.rotation = 0;
				this.scaleX = 1;
				this.scaleY = 1;
				this.lineWidth = 1;
			}
			draw(context){
				context.save();
				context.translate(this.x, this.y);
				context.rotate(this.rotation);
				context.strokeStyle = '#ccc';
				context.scale(this.scaleX, this.scaleY);
				context.lineWidth = this.lineWidth;
				context.beginPath();
				context.moveTo(this.x1, this.y1);
				context.lineTo(this.x2, this.y2);
				context.closePath();
				context.stroke();
				context.restore();
			}
		}
			
		for(let circle,i=0; i<numCircles; i++){
			circle = new Ball(4);
			circle.x = Math.random() * centerX;
			circle.y = Math.random() * centerY;
			circle.vx = Math.cos(parseInt(Math.random()*361,10) * Math.PI / 180);
			circle.vy = Math.cos(parseInt(Math.random()*361,10) * Math.PI / 180);
			circle.mass = 1;  //质量为1
			circles.push(circle);
		}
		
		function gravitate(partA){
			var dx = mouse.x - partA.x,
					dy = mouse.y - partA.y,
					distSQ = dx*dx + dy*dy,
					dist = Math.sqrt(distSQ),
					force = partA.mass * 10 / distSQ,
					ax = force * dx / dist,
					ay = force * dy / dist;
			partA.vx += ax / partA.mass;
			partA.vy += ay / partA.mass;
		}
		function move(partA){
			partA.x += partA.vx;
			partA.y += partA.vy;
			gravitate(partA);
		}
		function draw(circle){
			circle.draw(context);
		}
		
		(function drawFrame(){
			window.requestAnimationFrame(drawFrame, canvas);
			context.clearRect(0, 0, centerX, centerY);
			var left = 0, top = 0, right = canvas.width, bottom = canvas.height;
			
			circles.forEach((e)=>{
				let dx = mouse.x - e.x,
						dy = mouse.y - e.y;
						distance = Math.sqrt(dx*dx + dy*dy);
				move(e);	
				if(distance<=100){
					let line = new Line(mouse.x, mouse.y, e.x, e.y);
					line.draw(context);
				}
			
			});
			
			/*边界碰撞检测*/
			circles.forEach((e)=>{
				if(e.x + e.radius > right){
					e.x = right - e.radius;
					e.vx *= -1;
				}else if(e.x - e.radius < left){
					e.x = left + e.radius;
					e.vx *= -1;
				}
				if(e.y + e.radius > bottom){
					e.y = bottom - e.radius;
					e.vy *= -1;
				}else if(e.y - e.radius < top){
					e.y = top + e.radius;
					e.vy *= -1;
				}
				draw(e);
			});
		}());		
	</script>
</body>
</html>